package com.easychat.aspect;

import com.easychat.annotation.GlobalInterceptor;
import com.easychat.constants.Constants;
import com.easychat.entity.dto.TokenUserInfoDTO;
import com.easychat.entity.enums.ResponseCodeEnum;
import com.easychat.exception.BusinessException;
import com.easychat.utils.StringTools;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 使用AOP实现拦截器
 * 通过自定义注解指定切入点
 */
@Aspect
@Component
//@Slf4j
public class GlobalOperationAspect {

    @Resource
    private RedisTemplate redisTemplate;

    @Before("@annotation(com.easychat.annotation.GlobalInterceptor)")
    public void interceptorDo(JoinPoint joinPoint) {
        try {
            //signature->methodSignature->method->annotation获取注解
            Signature signature = joinPoint.getSignature();
            Method method = ((MethodSignature) signature).getMethod();
            GlobalInterceptor annotation = method.getAnnotation(GlobalInterceptor.class);
            if (annotation == null) {
                return;   //不需要校验
            }
            if (!annotation.checkLogin() && !annotation.checkAdmin()) {
                return;   //不需要校验
            }
            //进行校验
            checkLoginOperation(annotation.checkAdmin());
        } catch (BusinessException e) {
            //log.error("全局拦截异常：", e);
            throw e;
        } catch (Exception e) {
            //log.error("全局拦截异常：", e);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        } catch (Throwable t) {
            //log.error("全局拦截异常：", t);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        }
    }

    /**
     * 登录校验，若校验失败，则抛出异常
     * @param checkAdmin 是否校验管理员
     */
    private void checkLoginOperation(Boolean checkAdmin) {
        //获取http请求对象
        //TODO 用到了ThreadLocal
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        //获取token
        String token = request.getHeader("token");
        if (StringTools.isEmpty(token)) {
            //token为空，校验失败
            throw new BusinessException(ResponseCodeEnum.CODE_901);
        }
        //通过token在redis中获取对应的tokenUserInfoDTO
        TokenUserInfoDTO tokenUserInfoDTO = (TokenUserInfoDTO) redisTemplate.opsForValue().get(Constants.REDIS_KEY_WS_TOKEN + token);
        if (tokenUserInfoDTO == null) {
            //token对应的用户信息为空，校验失败
            throw new BusinessException(ResponseCodeEnum.CODE_901);
        }
        if (checkAdmin && !tokenUserInfoDTO.getAdmin()) {
            //需要校验管理员，但是发出此请求的不是管理员
            throw new BusinessException(ResponseCodeEnum.CODE_404);
        }
    }
}
